package org.moelab.trafficlight;

import java.net.*;
import java.util.*;
import java.util.concurrent.*;

import org.moelab.trafficlight.incoming.IncomingConfig;
import org.moelab.trafficlight.netty.ChannelForwardingHandler;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * @author xp
 */
public class Forwarder {

    private EventLoopGroup workers;

    public void open() {
        workers = new NioEventLoopGroup();
    }

    public void close() {
        workers.shutdownGracefully();
        workers = null;
    }

    public ChannelFuture income(IncomingConfig config, ChannelHandlerContext incomingContext, SocketAddress targetAddress) {
        ChannelInitializer<SocketChannel> channelInitializer = channelInitializerMap.get(incomingId);
        if (channelInitializer != null) {
            Bootstrap bootstrap = new Bootstrap()
                    .group(workers)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(channelInitializer);

            return bootstrap
                    .connect(targetAddress)
                    .addListener((ChannelFutureListener) future -> {
                        if (future.isSuccess()) {
                            Channel incomingChannel = incomingContext.channel();
                            Channel outgoingChannel = future.channel();

                            ChannelPipeline outgoingPipeline = outgoingChannel.pipeline();
                            outgoingPipeline.addLast(
                                    ChannelForwardingHandler.class.getName(),
                                    new ChannelForwardingHandler(incomingChannel));

                            ChannelPipeline incomingPipeline = incomingContext.pipeline();
                            incomingPipeline.addLast(
                                    ChannelForwardingHandler.class.getName(),
                                    new ChannelForwardingHandler(outgoingChannel));
                        }
                    });
        }
        return null;
    }
}
